import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import datetime
import json
from datetime import datetime, timedelta
import os
import sys
import math


class SatelliteCommSimulatorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("卫星通信仿真软件")
        self.root.geometry("1400x900")

        # 设置中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False

        # 初始化变量
        self.init_variables()

        # 创建主框架
        self.create_main_frames()

        # 初始化绘图
        self.init_plot()

        # 仿真控制变量
        self.simulation_running = False
        self.simulation_paused = False

    def init_variables(self):
        """初始化所有输入变量"""
        # 飞行器参数
        self.eirp_var = tk.StringVar(value="40.5")  # dBW
        self.speed_var = tk.StringVar(value="5.0")  # Ma

        # 飞行器位置参数
        self.start_lon_var = tk.StringVar(value="116.4")  # 经度
        self.end_lon_var = tk.StringVar(value="121.5")  # 经度
        self.start_lat_var = tk.StringVar(value="39.9")  # 纬度
        self.end_lat_var = tk.StringVar(value="31.2")  # 纬度
        self.start_alt_var = tk.StringVar(value="500")  # km
        self.end_alt_var = tk.StringVar(value="500")  # km

        # 信道参数
        self.distance_var = tk.StringVar(value="10000")  # km
        self.other_attenuation_var = tk.StringVar(value="2.0")  # dB

        # 卫星参数
        self.g_t_var = tk.StringVar(value="15.0")  # dB/K

        # 波形参数
        self.rate_var = tk.StringVar(value="1e6")  # bps
        self.freq_var = tk.StringVar(value="2e9")  # Hz
        self.modulation_var = tk.StringVar(value="BPSK")

        # 仿真时间变量
        self.sim_year_var = tk.StringVar(value=datetime.now().strftime("%Y"))
        self.sim_month_var = tk.StringVar(value=datetime.now().strftime("%m"))
        self.sim_day_var = tk.StringVar(value=datetime.now().strftime("%d"))
        self.sim_hour_var = tk.StringVar(value=datetime.now().strftime("%H"))
        self.sim_minute_var = tk.StringVar(value=datetime.now().strftime("%M"))
        self.sim_second_var = tk.StringVar(value=datetime.now().strftime("%S"))

        end_time = datetime.now() + timedelta(hours=1)
        self.end_year_var = tk.StringVar(value=end_time.strftime("%Y"))
        self.end_month_var = tk.StringVar(value=end_time.strftime("%m"))
        self.end_day_var = tk.StringVar(value=end_time.strftime("%d"))
        self.end_hour_var = tk.StringVar(value=end_time.strftime("%H"))
        self.end_minute_var = tk.StringVar(value=end_time.strftime("%M"))
        self.end_second_var = tk.StringVar(value=end_time.strftime("%S"))

        # 日志文本
        self.log_text = ""

        # 绘图数据
        self.plot_data = {
            "distance": [],
            "doppler": [],
            "snr": [],
            "ber": [],
            "time": []
        }

    def create_main_frames(self):
        """创建主框架"""
        # 主框架分为左右两部分
        main_frame = tk.Frame(self.root, bd=2, relief="solid")
        main_frame.pack(fill="both", expand=True, padx=10, pady=5)

        # 左侧参数框架
        left_frame = tk.Frame(main_frame, bd=2, relief="solid")
        left_frame.pack(side="left", fill="y", padx=5, pady=5)

        # 右侧图形和按钮框架
        right_frame = tk.Frame(main_frame, bd=2, relief="solid")
        right_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5)

        # 创建左侧参数框架
        self.create_parameter_frames(left_frame)

        # 创建右侧图形和按钮框架
        self.create_display_frames(right_frame)
        self.create_control_buttons(right_frame)

        # 创建日志框架
        self.create_log_frame()

    def create_parameter_frames(self, parent):
        """创建参数输入框架"""
        # 通信场景设置
        comm_scene_frame = ttk.LabelFrame(parent, text="一、通信场景设置", borderwidth=2, relief="solid")
        comm_scene_frame.pack(fill="x", padx=5, pady=5)

        # 1. 飞行器参数设置
        aircraft_frame = ttk.LabelFrame(comm_scene_frame, text="1. 飞行器参数设置", borderwidth=2, relief="solid")
        aircraft_frame.pack(fill="x", padx=5, pady=5)

        # 发射机EIRP和飞行器速度放在同一行
        row0 = ttk.Frame(aircraft_frame)
        row0.pack(fill="x", pady=2)
        ttk.Label(row0, text="发射机EIRP (dBW):").pack(side="left", padx=5)
        ttk.Entry(row0, textvariable=self.eirp_var, width=10).pack(side="left", padx=5)
        ttk.Label(row0, text="飞行器速度 (Ma):").pack(side="left", padx=5)
        ttk.Entry(row0, textvariable=self.speed_var, width=10).pack(side="left", padx=5)

        # 起始位置
        row1 = ttk.Frame(aircraft_frame)
        row1.pack(fill="x", pady=2)
        ttk.Label(row1, text="起始位置:").pack(side="left", padx=5)
        ttk.Label(row1, text="经度:").pack(side="left", padx=2)
        ttk.Entry(row1, textvariable=self.start_lon_var, width=8).pack(side="left", padx=2)
        ttk.Label(row1, text="纬度:").pack(side="left", padx=2)
        ttk.Entry(row1, textvariable=self.start_lat_var, width=8).pack(side="left", padx=2)
        ttk.Label(row1, text="高度:").pack(side="left", padx=2)
        ttk.Entry(row1, textvariable=self.start_alt_var, width=8).pack(side="left", padx=2)
        ttk.Label(row1, text="km").pack(side="left", padx=2)

        # 终止位置
        row2 = ttk.Frame(aircraft_frame)
        row2.pack(fill="x", pady=2)
        ttk.Label(row2, text="终止位置:").pack(side="left", padx=5)
        ttk.Label(row2, text="经度:").pack(side="left", padx=2)
        ttk.Entry(row2, textvariable=self.end_lon_var, width=8).pack(side="left", padx=2)
        ttk.Label(row2, text="纬度:").pack(side="left", padx=2)
        ttk.Entry(row2, textvariable=self.end_lat_var, width=8).pack(side="left", padx=2)
        ttk.Label(row2, text="高度:").pack(side="left", padx=2)
        ttk.Entry(row2, textvariable=self.end_alt_var, width=8).pack(side="left", padx=2)
        ttk.Label(row2, text="km").pack(side="left", padx=2)

        # 2. 信道参数设置
        channel_frame = ttk.LabelFrame(comm_scene_frame, text="2. 信道参数设置", borderwidth=2, relief="solid")
        channel_frame.pack(fill="x", padx=5, pady=5)

        # 通信距离和其他衰减放在同一行
        row3 = ttk.Frame(channel_frame)
        row3.pack(fill="x", pady=2)
        ttk.Label(row3, text="通信距离 (km):").pack(side="left", padx=5)
        ttk.Entry(row3, textvariable=self.distance_var, width=10).pack(side="left", padx=5)
        ttk.Label(row3, text="其他衰减 (dB):").pack(side="left", padx=5)
        ttk.Entry(row3, textvariable=self.other_attenuation_var, width=10).pack(side="left", padx=5)

        # 3. 卫星参数设置
        satellite_frame = ttk.LabelFrame(comm_scene_frame, text="3. 卫星参数设置", borderwidth=2, relief="solid")
        satellite_frame.pack(fill="x", padx=5, pady=5)

        ttk.Label(satellite_frame, text="接收机 G/T (dB/K):").grid(row=0, column=0, sticky="e", padx=5, pady=2)
        ttk.Entry(satellite_frame, textvariable=self.g_t_var, width=15).grid(row=0, column=1, sticky="w", padx=5,
                                                                             pady=2)

        ttk.Button(satellite_frame, text="选择卫星轨道参数文件",
                   command=self.load_satellite_orbit_file, width=20).grid(row=1, column=0, columnspan=2, pady=5)

        # 二、波形参数设置
        waveform_frame = ttk.LabelFrame(parent, text="二、波形参数设置", borderwidth=2, relief="solid")
        waveform_frame.pack(fill="x", padx=5, pady=5)

        # 调制类型
        ttk.Label(waveform_frame, text="调制类型:").grid(row=0, column=0, sticky="e", padx=5, pady=2)
        modulation_options = ["BPSK", "QPSK", "8PSK", "QAM16", "QAM64", "OFDM"]
        ttk.Combobox(waveform_frame, textvariable=self.modulation_var,
                     values=modulation_options, width=15, state="readonly").grid(row=0, column=1, sticky="w", padx=5,
                                                                                 pady=2)

        # 信息速率和通信频点放在同一行
        row4 = ttk.Frame(waveform_frame)
        row4.grid(row=1, column=0, columnspan=2, pady=2)
        ttk.Label(row4, text="信息速率 (bps):").pack(side="left", padx=5)
        ttk.Entry(row4, textvariable=self.rate_var, width=15).pack(side="left", padx=5)
        ttk.Label(row4, text="通信频点 (Hz):").pack(side="left", padx=5)
        ttk.Entry(row4, textvariable=self.freq_var, width=15).pack(side="left", padx=5)

        # 三、仿真参数设置
        sim_frame = ttk.LabelFrame(parent, text="三、仿真参数设置", borderwidth=2, relief="solid")
        sim_frame.pack(fill="x", padx=5, pady=5)

        # 仿真起始时间
        start_time_frame = ttk.LabelFrame(sim_frame, text="仿真起始时间", borderwidth=2, relief="solid")
        start_time_frame.grid(row=0, column=0, padx=5, pady=2, sticky="w")

        ttk.Label(start_time_frame, text="年").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_year_var, width=5).pack(side="left", padx=2)
        ttk.Label(start_time_frame, text="月").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_month_var, width=3).pack(side="left", padx=2)
        ttk.Label(start_time_frame, text="日").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_day_var, width=3).pack(side="left", padx=2)
        ttk.Label(start_time_frame, text="时").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_hour_var, width=3).pack(side="left", padx=2)
        ttk.Label(start_time_frame, text="分").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_minute_var, width=3).pack(side="left", padx=2)
        ttk.Label(start_time_frame, text="秒").pack(side="left")
        ttk.Entry(start_time_frame, textvariable=self.sim_second_var, width=3).pack(side="left", padx=2)

        # 仿真结束时间
        end_time_frame = ttk.LabelFrame(sim_frame, text="仿真结束时间", borderwidth=2, relief="solid")
        end_time_frame.grid(row=1, column=0, padx=5, pady=2, sticky="w")

        ttk.Label(end_time_frame, text="年").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_year_var, width=5).pack(side="left", padx=2)
        ttk.Label(end_time_frame, text="月").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_month_var, width=3).pack(side="left", padx=2)
        ttk.Label(end_time_frame, text="日").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_day_var, width=3).pack(side="left", padx=2)
        ttk.Label(end_time_frame, text="时").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_hour_var, width=3).pack(side="left", padx=2)
        ttk.Label(end_time_frame, text="分").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_minute_var, width=3).pack(side="left", padx=2)
        ttk.Label(end_time_frame, text="秒").pack(side="left")
        ttk.Entry(end_time_frame, textvariable=self.end_second_var, width=3).pack(side="left", padx=2)

    def create_display_frames(self, parent):
        """创建图形显示框架"""
        display_frame = ttk.LabelFrame(parent, text="仿真结果图形", borderwidth=2, relief="solid")
        display_frame.pack(fill="both", expand=True, padx=5, pady=5)

        # 创建4个子图
        self.fig, self.axs = plt.subplots(2, 2, figsize=(10, 8))
        self.fig.suptitle('卫星通信仿真结果', fontsize=16)

        self.canvas = FigureCanvasTkAgg(self.fig, master=display_frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(fill="both", expand=True)

    def create_control_buttons(self, parent):
        """创建控制按钮框架"""
        btn_frame = ttk.Frame(parent, borderwidth=2, relief="solid")
        btn_frame.pack(fill="x", padx=5, pady=5)

        # 控制按钮放在右侧，不占用整个宽度
        btn_subframe = ttk.Frame(btn_frame)
        btn_subframe.pack(side="right", padx=5, pady=5)

        self.start_btn = ttk.Button(btn_subframe, text="启动仿真", command=self.start_simulation, width=15)
        self.start_btn.grid(row=0, column=0, padx=5, pady=2)

        self.pause_btn = ttk.Button(btn_subframe, text="暂停仿真", command=self.pause_simulation, width=15,
                                    state="disabled")
        self.pause_btn.grid(row=0, column=1, padx=5, pady=2)

        self.resume_btn = ttk.Button(btn_subframe, text="继续仿真", command=self.resume_simulation, width=15,
                                     state="disabled")
        self.resume_btn.grid(row=0, column=2, padx=5, pady=2)

        self.stop_btn = ttk.Button(btn_subframe, text="停止仿真", command=self.stop_simulation, width=15,
                                   state="disabled")
        self.stop_btn.grid(row=0, column=3, padx=5, pady=2)

        ttk.Button(btn_subframe, text="保存参数设置", command=self.save_settings, width=15).grid(row=0, column=4,
                                                                                                 padx=5, pady=2)

    def create_log_frame(self):
        """创建日志显示框架"""
        log_frame = ttk.LabelFrame(self.root, text="日志显示", borderwidth=2, relief="solid")
        log_frame.pack(fill="both", expand=True, padx=10, pady=5)

        self.log_display = tk.Text(log_frame, height=10, wrap="word", font=('Consolas', 10))
        self.log_display.pack(fill="both", expand=True, padx=5, pady=5)

        scrollbar = ttk.Scrollbar(log_frame, command=self.log_display.yview)
        scrollbar.pack(side="right", fill="y")
        self.log_display.config(yscrollcommand=scrollbar.set)

    def init_plot(self):
        """初始化绘图"""
        for ax in self.axs.flat:
            ax.clear()
            ax.grid(True)

        titles = ["飞行器与卫星距离曲线", "飞行器运行时间与卫星多普勒曲线",
                  "接收机信噪比曲线", "接收机误码率曲线"]
        ylabels = ["距离 (km)", "多普勒频移 (kHz)", "SNR (dB)", "BER (log10)"]

        for ax, title, ylabel in zip(self.axs.flat, titles, ylabels):
            ax.set_title(title)
            ax.set_xlabel('时间 (s)')
            ax.set_ylabel(ylabel)

        # 设置坐标轴范围
        self.axs[0, 0].set_xlim(0, 6000)
        self.axs[0, 0].set_ylim(0, 10000)
        self.axs[0, 0].set_xticks(np.arange(0, 6001, 1000))
        self.axs[0, 0].set_yticks(np.arange(0, 10001, 2000))

        self.axs[0, 1].set_xlim(0, 6000)
        self.axs[0, 1].set_ylim(-500, 500)
        self.axs[0, 1].set_xticks(np.arange(0, 6001, 1000))
        self.axs[0, 1].set_yticks(np.arange(-500, 501, 200))

        self.axs[1, 0].set_xlim(0, 6000)
        self.axs[1, 0].set_ylim(-10, 30)
        self.axs[1, 0].set_xticks(np.arange(0, 6001, 1000))
        self.axs[1, 0].set_yticks(np.arange(-10, 31, 10))

        self.axs[1, 1].set_xlim(0, 6000)
        self.axs[1, 1].set_ylim(-10, 0)
        self.axs[1, 1].set_xticks(np.arange(0, 6001, 1000))
        self.axs[1, 1].set_yticks(np.arange(-10, 1, 2))
        self.axs[1, 1].set_yticklabels([f"10^{i}" for i in range(-10, 1, 2)])

        self.canvas.draw()

    def load_satellite_orbit_file(self):
        """加载卫星轨道示例参数文件"""
        file_path = filedialog.askopenfilename(
            title="选择卫星轨道参数文件",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )

        if file_path:
            try:
                with open(file_path, 'r') as f:
                    data = json.load(f)

                # 更新参数
                params = {
                    "eirp": self.eirp_var,
                    "speed": self.speed_var,
                    "start_lon": self.start_lon_var,
                    "end_lon": self.end_lon_var,
                    "start_lat": self.start_lat_var,
                    "end_lat": self.end_lat_var,
                    "start_alt": self.start_alt_var,
                    "end_alt": self.end_alt_var,
                    "distance": self.distance_var,
                    "other_attenuation": self.other_attenuation_var,
                    "g_t": self.g_t_var,
                    "rate": self.rate_var,
                    "freq": self.freq_var,
                    "modulation": self.modulation_var,
                }

                for key, var in params.items():
                    if key in data:
                        var.set(data[key])

                # 更新仿真时间
                if "start_time" in data:
                    start_time = datetime.strptime(data["start_time"], "%Y-%m-%d %H:%M:%S")
                    self.sim_year_var.set(start_time.strftime("%Y"))
                    self.sim_month_var.set(start_time.strftime("%m"))
                    self.sim_day_var.set(start_time.strftime("%d"))
                    self.sim_hour_var.set(start_time.strftime("%H"))
                    self.sim_minute_var.set(start_time.strftime("%M"))
                    self.sim_second_var.set(start_time.strftime("%S"))

                if "end_time" in data:
                    end_time = datetime.strptime(data["end_time"], "%Y-%m-%d %H:%M:%S")
                    self.end_year_var.set(end_time.strftime("%Y"))
                    self.end_month_var.set(end_time.strftime("%m"))
                    self.end_day_var.set(end_time.strftime("%d"))
                    self.end_hour_var.set(end_time.strftime("%H"))
                    self.end_minute_var.set(end_time.strftime("%M"))
                    self.end_second_var.set(end_time.strftime("%S"))

                self.log(f"成功加载参数文件: {os.path.basename(file_path)}")

            except Exception as e:
                self.log(f"加载文件失败: {str(e)}")
                messagebox.showerror("错误", f"无法加载文件:\n{str(e)}")

    def start_simulation(self):
        """启动仿真"""
        if self.simulation_running:
            self.log("仿真已经在运行中")
            return

        if not self.validate_parameters():
            return

        self.simulation_running = True
        self.simulation_paused = False

        # 清空旧数据
        self.plot_data = {key: [] for key in self.plot_data}

        # 更新按钮状态
        self.start_btn.config(state="disabled")
        self.pause_btn.config(state="normal")
        self.stop_btn.config(state="normal")

        self.log("仿真开始...")
        self.log_current_parameters()

        # 开始仿真
        self.simulate_progress()

    def get_simulation_time(self):
        """获取仿真时间"""
        try:
            start_time = datetime(
                year=int(self.sim_year_var.get()),
                month=int(self.sim_month_var.get()),
                day=int(self.sim_day_var.get()),
                hour=int(self.sim_hour_var.get()),
                minute=int(self.sim_minute_var.get()),
                second=int(self.sim_second_var.get())
            )

            end_time = datetime(
                year=int(self.end_year_var.get()),
                month=int(self.end_month_var.get()),
                day=int(self.end_day_var.get()),
                hour=int(self.end_hour_var.get()),
                minute=int(self.end_minute_var.get()),
                second=int(self.end_second_var.get())
            )

            return start_time, end_time
        except ValueError as e:
            self.log(f"时间格式错误: {str(e)}")
            return None, None

    def log_current_parameters(self):
        """记录当前参数设置"""
        self.log("当前参数设置:")
        self.log(f"发射机EIRP: {self.eirp_var.get()} dBW")
        self.log(f"飞行器速度: {self.speed_var.get()} Ma")
        self.log(
            f"起始位置: 经度 {self.start_lon_var.get()}°, 纬度 {self.start_lat_var.get()}°, 高度 {self.start_alt_var.get()} km")
        self.log(
            f"终止位置: 经度 {self.end_lon_var.get()}°, 纬度 {self.end_lat_var.get()}°, 高度 {self.end_alt_var.get()} km")
        self.log(f"通信距离: {self.distance_var.get()} km")
        self.log(f"其他衰减: {self.other_attenuation_var.get()} dB")
        self.log(f"接收机G/T: {self.g_t_var.get()} dB/K")
        self.log(f"调制类型: {self.modulation_var.get()}")
        self.log(f"信息速率: {self.rate_var.get()} bps")
        self.log(f"通信频点: {self.freq_var.get()} Hz")

        start_time, end_time = self.get_simulation_time()
        if start_time and end_time:
            self.log(
                f"仿真时间: 从 {start_time.strftime('%Y-%m-%d %H:%M:%S')} 到 {end_time.strftime('%Y-%m-%d %H:%M:%S')}")

    def simulate_progress(self):
        """执行仿真过程"""
        if not self.simulation_running or self.simulation_paused:
            return

        start_time, end_time = self.get_simulation_time()
        if not start_time or not end_time:
            self.simulation_running = False
            return

        total_seconds = (end_time - start_time).total_seconds()

        steps = 100
        for i in range(1, steps + 1):
            if not self.simulation_running:
                break

            while self.simulation_paused:
                if not self.simulation_running:
                    return
                self.root.update()
                self.root.after(100)

            # 生成数据点
            t = total_seconds * i / steps
            self.generate_data_point(t)

            # 更新显示
            if i % 10 == 0 or i == steps:
                self.update_plot()
                self.update_result_table()

            self.root.update()
            self.root.after(50)

        if self.simulation_running:
            self.simulation_running = False
            self.log("仿真完成")

            # 恢复按钮状态
            self.start_btn.config(state="normal")
            self.pause_btn.config(state="disabled")
            self.resume_btn.config(state="disabled")
            self.stop_btn.config(state="disabled")

    def generate_data_point(self, t):
        """生成仿真数据点"""
        self.plot_data["time"].append(t)

        # 计算距离 (km) - 0-10000km
        distance = 5000 + 5000 * np.sin(t * np.pi / 3000)
        self.plot_data["distance"].append(distance)

        # 计算多普勒频移 (kHz) - -500到500kHz
        if len(self.plot_data["time"]) > 1:
            dt = self.plot_data["time"][-1] - self.plot_data["time"][-2]
            dd = self.plot_data["distance"][-1] - self.plot_data["distance"][-2]
            velocity = dd / dt  # km/s
            doppler = velocity * float(self.freq_var.get()) / 3e5 / 1000  # 转换为kHz
            self.plot_data["doppler"].append(doppler)
        else:
            self.plot_data["doppler"].append(0)

        # 计算信噪比 (dB) - -10到30dB
        snr = 10 + 10 * np.sin(t * np.pi / 3000 + np.pi / 2)
        self.plot_data["snr"].append(snr)

        # 计算误码率 (log10) - 10^-10到10^0
        ber_log = -10 + 10 * (1 - np.sin(t * np.pi / 6000 + np.pi / 2))
        self.plot_data["ber"].append(ber_log)

    def update_plot(self):
        """更新绘图"""
        if not self.plot_data["time"]:
            return

        t = self.plot_data["time"]

        # 清除旧图形
        for ax in self.axs.flat:
            ax.clear()

        # 绘制曲线
        self.axs[0, 0].plot(t, self.plot_data["distance"], label='距离', color='blue')
        self.axs[0, 1].plot(t, self.plot_data["doppler"], label='多普勒', color='green')
        self.axs[1, 0].plot(t, self.plot_data["snr"], label='信噪比', color='red')
        self.axs[1, 1].plot(t, self.plot_data["ber"], label='误码率', color='purple')

        # 设置图表属性
        titles = ["飞行器与卫星的距离", "飞行器与卫星的多普勒",
                  "接收机信噪比", "接收机误码率"]
        ylabels = ["距离 (km)", "多普勒频移 (kHz)", "SNR (dB)", "BER (log10)"]

        for ax, title, ylabel in zip(self.axs.flat, titles, ylabels):
            ax.set_title(title)
            ax.set_xlabel('时间 (s)')
            ax.set_ylabel(ylabel)
            ax.grid(True)
            ax.legend()

        # 设置坐标轴范围
        self.axs[0, 0].set_xlim(0, 6000)
        self.axs[0, 0].set_ylim(0, 10000)
        self.axs[0, 0].set_xticks(np.arange(0, 6001, 1000))
        self.axs[0, 0].set_yticks(np.arange(0, 10001, 2000))

        self.axs[0, 1].set_xlim(0, 6000)
        self.axs[0, 1].set_ylim(-500, 500)
        self.axs[0, 1].set_xticks(np.arange(0, 6001, 1000))
        self.axs[0, 1].set_yticks(np.arange(-500, 501, 200))

        self.axs[1, 0].set_xlim(0, 6000)
        self.axs[1, 0].set_ylim(-10, 30)
        self.axs[1, 0].set_xticks(np.arange(0, 6001, 1000))
        self.axs[1, 0].set_yticks(np.arange(-10, 31, 10))

        self.axs[1, 1].set_xlim(0, 6000)
        self.axs[1, 1].set_ylim(-10, 0)
        self.axs[1, 1].set_xticks(np.arange(0, 6001, 1000))
        self.axs[1, 1].set_yticks(np.arange(-10, 1, 2))
        self.axs[1, 1].set_yticklabels([f"10^{i}" for i in range(-10, 1, 2)])

        self.fig.tight_layout()
        self.canvas.draw()

    def update_result_table(self):
        """更新结果表格"""
        pass

    def pause_simulation(self):
        """暂停仿真"""
        if not self.simulation_running:
            return

        self.simulation_paused = True
        self.pause_btn.config(state="disabled")
        self.resume_btn.config(state="normal")
        self.log("仿真已暂停")

    def resume_simulation(self):
        """继续仿真"""
        if not self.simulation_running or not self.simulation_paused:
            return

        self.simulation_paused = False
        self.pause_btn.config(state="normal")
        self.resume_btn.config(state="disabled")
        self.log("仿真继续...")

        # 继续仿真
        self.simulate_progress()

    def stop_simulation(self):
        """停止仿真"""
        self.simulation_running = False
        self.simulation_paused = False

        # 更新按钮状态
        self.start_btn.config(state="normal")
        self.pause_btn.config(state="disabled")
        self.resume_btn.config(state="disabled")
        self.stop_btn.config(state="disabled")

        self.log("仿真已停止")

    def save_settings(self):
        """保存参数设置"""
        file_path = filedialog.asksaveasfilename(
            title="保存参数设置",
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
            initialfile="satcom_settings.json"
        )

        if file_path:
            try:
                start_time, end_time = self.get_simulation_time()

                settings = {
                    "eirp": self.eirp_var.get(),
                    "speed": self.speed_var.get(),
                    "start_lon": self.start_lon_var.get(),
                    "end_lon": self.end_lon_var.get(),
                    "start_lat": self.start_lat_var.get(),
                    "end_lat": self.end_lat_var.get(),
                    "start_alt": self.start_alt_var.get(),
                    "end_alt": self.end_alt_var.get(),
                    "distance": self.distance_var.get(),
                    "other_attenuation": self.other_attenuation_var.get(),
                    "g_t": self.g_t_var.get(),
                    "rate": self.rate_var.get(),
                    "freq": self.freq_var.get(),
                    "modulation": self.modulation_var.get(),
                }

                if start_time:
                    settings["start_time"] = start_time.strftime("%Y-%m-%d %H:%M:%S")
                if end_time:
                    settings["end_time"] = end_time.strftime("%Y-%m-%d %H:%M:%S")

                with open(file_path, 'w') as f:
                    json.dump(settings, f, indent=4)

                self.log(f"参数设置已保存到: {file_path}")
                messagebox.showinfo("成功", f"参数设置已保存到:\n{file_path}")

            except Exception as e:
                self.log(f"保存参数失败: {str(e)}")
                messagebox.showerror("错误", f"保存参数失败:\n{str(e)}")

    def log(self, message):
        """记录日志"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"
        self.log_display.insert(tk.END, log_message)
        self.log_display.see(tk.END)
        self.log_text += log_message

    def validate_parameters(self):
        """验证输入参数"""
        try:
            # 验证数值参数
            params = [
                ("EIRP", self.eirp_var.get(), float, 0, 100),
                ("飞行速度", self.speed_var.get(), float, 0, 20),
                ("起始经度", self.start_lon_var.get(), float, -180, 180),
                ("终止经度", self.end_lon_var.get(), float, -180, 180),
                ("起始纬度", self.start_lat_var.get(), float, -90, 90),
                ("终止纬度", self.end_lat_var.get(), float, -90, 90),
                ("起始高度", self.start_alt_var.get(), float, 0, 2000),
                ("终止高度", self.end_alt_var.get(), float, 0, 2000),
                ("距离", self.distance_var.get(), float, 100, 100000),
                ("其他衰减", self.other_attenuation_var.get(), float, 0, 100),
                ("接收机G/T", self.g_t_var.get(), float, -50, 50),
                ("信息速率", self.rate_var.get(), float, 1e3, 1e9),
                ("通信频点", self.freq_var.get(), float, 1e6, 100e9),
            ]

            for name, value, type_, min_, max_ in params:
                num = type_(value)
                if not (min_ <= num <= max_):
                    raise ValueError(f"{name}应在{min_}到{max_}之间")

            # 验证时间
            start_time, end_time = self.get_simulation_time()
            if not start_time or not end_time:
                raise ValueError("仿真时间格式不正确")

            if end_time <= start_time:
                raise ValueError("结束时间必须晚于开始时间")

            return True

        except ValueError as e:
            self.log(f"参数验证失败: {str(e)}")
            messagebox.showerror("参数错误", f"请检查参数输入:\n{str(e)}")
            return False


if __name__ == "__main__":
    try:
        root = tk.Tk()
        app = SatelliteCommSimulatorApp(root)


        # 确保窗口关闭时程序退出
        def on_closing():
            if messagebox.askokcancel("退出", "确定要退出卫星通信仿真软件吗？"):
                root.quit()


        root.protocol("WM_DELETE_WINDOW", on_closing)
        root.mainloop()

    except Exception as e:
        print(f"程序运行出错: {str(e)}")
        if os.name == "nt":
            input("按Enter键退出...")
        sys.exit(1)